パソコン活用研究ラピュタへの道(アセンブラ、DOS、Windows、旧型PCの活用研究)
PC2001ハード構成
1 はじめに
ついに登場してしまいました。PC2001内部ROM解体新書。
パソコンの起動から始まって、Operating Systemがどのようにパソコンを制御しているのか、
その仕組みを、昔のシンプルな8Bit機をまな板の上にのせて、ずばり解体。
BASICで print"A" と書けば画面には いとも簡単にA と表示されますが、パソコンの起動から始まって
A
の表示まで、パソコン内部では(機械語レベルでは)実に壮大なドラマが演じれれております。
パソコンはいかにして動いているのか、その壮大なドラマを逐一解析してみたいと思います。
まずは、一番シンプルなパソコンPC2001を題材にその内部ROMを解析していきましょう。
実はこの企画、元来、PC2001のBASICプログラムをRS232Cを使ってWINDOWS機におとす
というプロジェクトに端を発しています。PC2001のROMを流用してBASICプログラムをRS232C
でダウン&アップロードする機械語プログラムができないかと考えて、ROMの解析をはじめたのが
そもそもの始まりです。RS232Cプロジェクト自体は「/旧パソコン活用/RS232C交信」にまとめ
ましたので、そちらを参照して下さい。
なお、PC2001の技術資料はほとんどなく、おじさんが独自に解析、推定した部分がかなりあります。
間違っている部分もあると思いますが、そこはご容赦下さい。
2 PC2001ハード構成
今更、この博物館いきの古い機械のハードを詳述しても仕方ないので、今後の説明に必要となる部分のみ
記述いたします。
CPU、レジスタ
CPUはNECのμCOM87というインテル8080に似たものです。
レジスタは A,B,C,D,E,H,Lおよび PC,SP です。 BC,DE,HLはペアで使用可です。
たてづみ命令
特殊機能として、同種の命令を連続して置いて実行させると、最初の命令を実行した後は、以降の同種命令
をNOPとみなす、という機能があります。このたてづみ命令の使えるのは MVI
A, byte
MVI L, byte LXI H, word の三種類です。
例えば
L1 MVI, A, 1H
L2 MVI A, 2H
L3 MVI A, 3H
L4 MVI A, 4H
とたてづみされている場合、L2にジャンプあるいはコールがなされたとしたら、L3,
L4はNOPとみなされて、
レジスタAには2Hがロードされることになります。
コール命令
絶対番地をコールするcall命令の他に、CALF, CALTがあります。
CALFはコード1Byte,オペランド1Byteの2Byteよりなり、800HからFFFHをコールします。
コードの下位3bitとオペランドの8bitあわせて11bitでコール先(800H+11bit)が決定されます。
CALTは80HからFFHにあるCALT用アドレステーブルを参照してコールします。
コードの下位6bit * 2 + 80Hを参照します。
条件分岐
分岐命令にはジャンプとコールがありますが、全て無条件分岐です。μCOM87には条件ジャンプに相当
する命令がありません。演算命令の多くにスキップ条件というものがあり、スキップ条件を満たすと、次の
1命令を飛ばします。
プログラムステータスワード
いわゆるフラグレジスタに相当するものです。
CY キャリーフラグ Z ゼロフラグ
SK スキップフラグ スキップ条件が成立した時にセット
HC ハーフキャリフラグ
などがあります。
また、上述のたてづみ命令が実行された時にセットされるフラグとして
L0 MVI L, byte LXI H, word のたてづみ実行
L1 MVI A, byte のたてづみ実行
があります。
割り込み
割り込みは外部割り込み2つ(INT0, INT1)とタイマ割り込み(INTT)です。
8086等でのいわゆるソフトウエア割り込みに相当するものはありません。
それぞれの割り込みが発生すると、フラグINTF, INTF1, INTFTがセットされます。
このフラグの状態はSKNIT命令でチェックできます。
フラグにはもうひとつシリアルデータ転送(SIO命令)終了時にセットされるINTFSがあります。
これもSKNITでテストできます。
割り込み処理のエントリ以下の通り
INT0 が4H
INT1が10H タイマICより64Hz毎に発生させられる割り込み?キー入力チェックルーチン
はここにあります
INTTが8H タイマレジスタ(TM)、タイマモードレジスタ(TMM)の設定により一定のインターバル
で発生するタイマ割り込み
ソフトウエア割り込み的なものにCALT命令があります(後述)
割り込みたいするマスクフラグからなる割り込みマスクレジスタ(MK)があります。MKは通常の転送命令
論理演算命令でせっていできます。
ビット0 セットするとINT0をマスク
ビット1 セットするとINTTをマスク
ビット2 セットするとINT1をマスク
タイマ
STM命令によりタイマーがスタートし、タイマレジスタ(TM)とタイマモードレジスタのビット2(TMM2)
の値により、以下のインターバルで割り込み(INTT)が発生します。
それぞれのレジスタの設定には、MOV TM, A MOV TMM,A を使います。
TMの値 | TMM2=0の時 | TMM2=1の時 |
00 | 8 | 128 |
01 | 16 | 256 |
02 | 24 | 384 |
・・・・ | ||
FE | 2032 | 32512 |
FF | 2040 | 32640 |
メモリ
CPUスタート番地はおそらく0H(Hは16進数を表す)番地からです。
コールアドレステーブルが80HからFFHまであり CALT 命令が参照します。
CALT 0 80Hに格納されている番地をコール
CALT 63 FEHに格納されている番地をコール
FF00HからFFFFHはワーキングレジスタと呼ばれ、専用の短い命令でアクセスできます。
レジスタに近い使い方ができます。
STAW, LDAW, INRW, DCRWなどワーキンクレジスタ専用の命令があります。
I/O ポート
ポートA(PA) 8Bitの出力ポート
ポートB(PB) 8bitの入出力ポート。入出力はモードBレジスタ(MB)でビット単位で指定します。
0で出力モード 1で入力モードとなります。
ポートC(PC) 6Bitの入力ポート
ポートE(PE) 16Bitの出力ポートでアドレスバス兼用です。
PEX命令によりBレジスタの値がPE15-8に、Cレジスタの値がPE7-0に出力されます。
PER命令でアドレスバスとして使用します。
I/Oポートへのアクセスは、 MOV PA,A MOV A,PB 等の転送命令で行います。
ニモニック
8080に似たニモニックを使うので、8080でのコーディングの経験があればだいたい理解できると思います。
主要な部分のみピックアップします。
オペランドの表現
r A, B, C, D, E, H, L
rpa BC, DE, HL, DE+, HL+, DE-, HL-
irf INTF, INTF1, INTFT, INTFS
f CY(キャリーフラグ)、Z(ゼロフラグ)
wa ワーキングレジスタ(FF00HからFFFFH)の下位1Byteを示す即値
ニモニック | オペランド | オペレーション | スキップ条件/フラグ変化 | バイナリコード |
論理演算 | ||||
ANA | A,r | A<-A and r | 6089 -- 608f | |
ANAX | rpa | A<-A and (rpa) | 7089 --708f | |
GTA | A,r | A-r-1 | No Borrow/CY,Z | 60a9 --60af |
GTAX | rpa | A-(rpa)-1 | No Borrow/CY,Z | 70a9 --70af |
LTA | A,r | A-r | Borrow/CY,Z | 60b9 --60bf |
LTAX | rpa | A-(rpa) | Borrow/CY,Z | 70b9 -- 70bf |
NEA | A,r | A-r | No Zero/CY,Z | 60e9 --60ef |
NEAX | rpa | A-(rpa) | No Zero/CY,Z | 70e9 --70ef |
EQA | A,r | A-r | Zero/CY,Z | 60f9 -- 60ff |
ワーキングレジスタ 命令 |
||||
ANIW | wa,byte | (FFH,wa)<-(FFH,wa)and byte | /Z | 05,wa,byte |
ORIW | wa,byte | (FFH,wa)<-(FFH,wa) or byte | /Z | 15,wa,byte |
GTIW | wa,byte | (FFH,wa)<-(FFH,wa)-byte-1 | No Borrow/CY,Z | 25,wa,byte |
LTIW | wa,byte | (FFH,wa)<-(FFH,wa)-byte | Borrow/CY,Z | 35 ,wa,byte |
ONIW | wa,byte | (FFH,wa) and byte | No ZERO/Z | 45,wa,byte |
OFFIW | wa,byte | (FFH,wa) and byte | ZERO/Z | 55,wa,byte |
NEIW | wa,byte | (FFH,wa) -byte | No ZERO/CY,Z | 65,wa,byte |
EQIW | wa,byte | (FFH,wa)-byte | ZERO/CY,Z | 75 ,wa,byte |
コール命令 | ||||
CALL | word | pc<-word | 44 word | |
CALF | word | 上述 | 7800 --7ffff | |
CALT | word | 上述 | 80 -- bf | |
リターン命令 | ||||
RET | 08 | |||
RETS | リターン後の1命令 スキップ |
無条件SKIP | 18 | |
RETI | /CY,Z | 62 | ||
スキップ命令 | ||||
SKN | f | f=0ならskip | f=0 | 481a,481c |
SKINT | irf | irf=0ならskip そうでなければ int*をreset |
irf=0 | 4810-2,4 |
レジスタ制御 | ||||
SIO | シリアルI/Oスタート | 09 | ||
STM | タイマースタート | 19 | ||
ジャンプ | ||||
JMP | word | PC<-word | 54 word | |
JB | PC<-B,C | 73 | ||
JR | コードの下位6bit で-32から31の 範囲にジャンプ |
c0--ff | ||
JRE | コード最下位Bitと オペランドの9bit により-256から 255の範囲にジャンプ |
4e00-4fff | ||